﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;

namespace HHHFramework
{

    public class ResLoad
    {

        private List<Res> mResRecord = new List<Res>();

        #region API  resources 必须继承自System.Object
        /// <summary>
        /// 同步加载资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="assetName"></param>
        /// <returns></returns> 
        public T LoadSync<T>(string assetName, string assetBundleName ) where T : Object
        {

            return DoLoadSync<T>(assetName, assetBundleName);
        }

        /// <summary>
        /// 同步加载资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="assetName"></param>
        /// <returns></returns>
        public T LoadSync<T>(string assetName) where T : Object
        {
            var res = DoLoadSync<T>(assetName,null);
            //if (res==null) {
            //    Debug.LogError(res.name + "    " + typeof(T).ToString());
            //}           
            return res;
        }

        /// <summary>
        /// 异步加载资源
        /// </summary>
        /// <typeparam name="T">加载资源的类型</typeparam>
        /// <param name="assetName">加载资源的名称</param>
        /// <param name="onLoaded">回调函数</param>
        public void LoadAsync<T>(string assetName, Action<T> onLoaded) where T : Object
        {
            DoLoadAsync<T>(assetName, null, onLoaded);
        }

        /// <summary>
        /// 异步加载一个assetbundle中的资源
        /// </summary>
        /// <typeparam name="T">加载资源的类型</typeparam>
        /// <param name="assetName"> 加载资源的名称</param>
        /// <param name="assetBundleName">加载资源的assetbundle路径</param>
        /// <param name="onLoaded">回调函数</param>
        public void LoadAsync<T>(string assetName, string assetBundleName, Action<T> onLoaded) where T : Object
        {
            DoLoadAsync<T>(assetName, assetBundleName, onLoaded);
        }

        public void ReleaseRes<T>(string assetName, string assetBundleName =null)
        {
            ResSearchKeys resSearchKeys = ResSearchKeys.Allocate(assetName, assetBundleName, typeof(T));
            var res = mResRecord.Find(loadassets => loadassets.Equals(resSearchKeys));
            mResRecord.Remove(res);
            res.Release();
        }

        public void ReleaseRes(string assetName) {

        }

        public void ReleaseRes(Res assetRes)
        {
            var res = mResRecord.Find(loadassets => loadassets.Equals(assetRes));
            mResRecord.Remove(res);
            res.Release();
        }

        /// <summary>
        /// 一个页面释放了资源
        /// </summary>
        public void ReleaseAll()
        {
            mResRecord.ForEach(res => { res.Release(); });
            mResRecord.Clear();
        }

        #endregion

        #region 本地方法

        /// <summary>
        /// 同步加载资源
        /// </summary>
        /// <typeparam name="T"> 返回类型</typeparam>
        /// <param name="assetName">资源名称</param>
        /// <param name="assetBundleName">所属的assetbundle   也可以没有assetbundle归属</param>
        /// <param name="onLoaded"></param>
        /// <returns></returns>
        private T DoLoadSync<T>(string assetName, string ownerBundle) where T : Object
        {
            if (string.IsNullOrEmpty(ownerBundle))
            {
                ownerBundle = null;
            }
            ResSearchKeys resSearchKeys = ResSearchKeys.Allocate(assetName, ownerBundle, typeof(T));
            var res = GetRes(resSearchKeys);
            if (res != null)
            {
                if (res.State == ResState.Loading)
                {
                    throw new System.Exception("请不要在异步加载资源的同时加载资源");
                }
                else if (res.State == ResState.Loaded)
                {
                    return res.Asset as T;
                }
            }
           
            res = CreateRes(resSearchKeys);
            res.LoadSync();
            T asset = res.Asset as T;
            return asset;
        }

        /// <summary>
        /// 异步加载资源
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="assetName">资源名称</param>
        /// <param name="assetBundleName">所属的assetbundle   也可以没有assetbundle归属</param>
        /// <param name="onLoaded"></param>
        /// <returns></returns>
        private void DoLoadAsync<T>(string assetName, string ownerBundle, Action<T> onLoaded) where T : Object
        {
            if (string.IsNullOrEmpty(ownerBundle)) {
                ownerBundle = null;
            }
            ResSearchKeys resSearchKeys = ResSearchKeys.Allocate(assetName, ownerBundle, typeof(T));
            //查找存在资源
            var res = GetRes(resSearchKeys);
            Action<Res> onResLoaded = null;
            onResLoaded = loadedRes =>
            {
                onLoaded(res.Asset as T);
                res.UnRegisterOnLoadedEvent(onResLoaded);
            };
            if (res != null)
            {
                switch (res.State)
                {

                    case ResState.Loading:
                        {
                            res.RegisterOnLoadedEvent(onResLoaded);
                        }
                        break;
                    case ResState.Loaded:
                        {
                            onLoaded(res.Asset as T);
                        }

                        break;
                }
                return;
            }
         
            //创建的时候就直接添加进去了   如果加载错误数组中还是有这个资源类
            res = CreateRes(resSearchKeys);
            res.RegisterOnLoadedEvent(onResLoaded);
            res.LoadAsync();
        }

        /// <summary>
        /// 查找本地资源
        /// </summary>
        /// <param name="assetName"></param>
        /// <returns></returns>
        private Res GetResFromRecord(ResSearchKeys resSearchKeys)
        {          
            return mResRecord.Find(loadassets =>  loadassets.Equals(resSearchKeys));
        }

        /// <summary>
        /// 查找全局资源
        /// </summary>
        /// <param name="assetName"></param>
        /// <returns></returns>
        private Res GetResFromMgr(ResSearchKeys resSearchKeys)
        {
            return ResMgr.Instance.sharedLoadRes.Find(loadassets => loadassets.Equals(resSearchKeys));
        }

        /// <summary>
        /// 不存在当前Res的时候 创建
        /// </summary>
        /// <param name="assetName">资源名称</param>
        /// <param name="owenBundle">如果加载assetbundle中的资源 owerbundle等于所属的assetbundle</param>
        /// <returns></returns>
        private Res CreateRes(ResSearchKeys resSearchKeys)
        {
            Res res = ResFactory.Create(resSearchKeys);
            ResMgr.Instance.sharedLoadRes.Add(res);
            AddResToRecord(res);
            return res;
        }

        /// <summary>
        /// 添加全局资源到本地资源
        /// </summary>
        /// <param name="resFromResMgr"></param>
        private void AddResToRecord(Res resFromResMgr)
        {
            mResRecord.Add(resFromResMgr);
            resFromResMgr.Retain();
        }

        private Res GetRes(ResSearchKeys resSearchKeys)
        {
            //查找当前资源记录
            var res = GetResFromRecord(resSearchKeys);
            if (res != null)
            {
                return res;
            }
            //查找全局的资源池
            res = GetResFromMgr(resSearchKeys);
            if (res != null)
            {
                AddResToRecord(res);
                return res;
            }
            return null;
        }

        public int GetRecordNumber()
        {
            return mResRecord.Count;
        }
        #endregion
    }
}